package com.xzzz.irda.guardcat.server.metric;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import com.xzzz.irda.guardcat.server.app.pojo.MachineInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 创建拉取任务的工厂类
 *
 * @author xzzz
 */
@Slf4j
@Component
public class MetricFetchJobFactory implements ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {

    private static final String METRIC_FETCH_JOB_PACKAGE = "com.xzzz.irda.guardcat.server.metric";
    private static final Class<?> METRIC_FETCH_JOB_CLASS = MetricFetchJob.class;
    private static final Set<Class<?>> JOBS = new HashSet<>();
    private static final Map<Class<?>, MetricRepository> REPOS = new HashMap<>();

    private ApplicationContext applicationContext;

    static {
        Set<Class<?>> jobClass = ClassUtil.scanPackageBySuper(METRIC_FETCH_JOB_PACKAGE, METRIC_FETCH_JOB_CLASS);
        for (Class<?> job : jobClass) {
            Repository repository = AnnotationUtil.getAnnotation(job, Repository.class);
            if (repository == null) {
                log.warn("[GUARDCAT] 拉取任务 [{}] 未使用 @Repository 注解绑定存储类, 已忽略", job.getName());
                continue;
            } else {
                if (!repository.enabled()) {
                    log.warn("[GUARDCAT] 拉取任务 [{}] 被禁用, 已忽略", job.getName());
                    continue;
                }
            }
            JOBS.add(job);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 容器初始化完成后建立 task 和 {@link Repository} 的映射关系
     */
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.init();
    }

    /**
     * 容器初始化完成后建立 task 和 {@link Repository} 的映射关系
     */
    public void init() {
        for (Class<?> job : JOBS) {
            Repository repository = AnnotationUtil.getAnnotation(job, Repository.class);
            Class<? extends MetricRepository> metricRepository = repository.repo();
            REPOS.put(job, applicationContext.getAutowireCapableBeanFactory().getBean(metricRepository));
        }
        StringBuilder sb = new StringBuilder();
        REPOS.forEach((k, v) -> sb.append("[")
                .append(k.getSimpleName()).append(" > ")
                .append(v.getClass().getSimpleName())
                .append("]"));
        log.info("[GUARDCAT] 启用的拉取任务如下: {}", sb.toString());
    }


    public static List<MetricFetchJob<?>> build(MachineInfo machineInfo) {
        List<MetricFetchJob<?>> taskList = new ArrayList<>();
        for (Class<?> task : JOBS) {
            MetricFetchJob<?> taskInstance = (MetricFetchJob<?>) ReflectUtil.newInstance(task, machineInfo, REPOS.get(task));
            taskList.add(taskInstance);
        }
        return taskList;
    }

}
